package com.jiao.table.config;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.jiao.comm.PackageScann;
import com.jiao.comm.exception.LoadException;
import com.jiao.comm.utils.LogUtil;
import com.jiao.datasource.listener.ConnectionListener;
import com.jiao.datasource.listener.ListenerExce;
import com.jiao.datasource.listener.SQLListener;
import com.jiao.support.cache.DynamicCache;
import com.jiao.table.annotation.TableCache;
import com.jiao.table.cache.DynamicCacheWrite;
import com.jiao.table.entity.TableInfo;
import com.jiao.table.jdbc.TableMapperService;
import lombok.Getter;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 缓存数据加载.
 * @Author: vincent.jiao
 * @Date: 2021/6/11
 */
@Component
public class CacheDataLoad implements ApplicationListener<ContextRefreshedEvent> {
    private final static Map<Class, TableInfo> tableInfoCacheMap = new ConcurrentHashMap<>(128);
    private final static Map<String, Class> tableEntityClassCacheMap = new ConcurrentHashMap<>(128);
    private static ApplicationContext applicationContext = null;

    public static void putTableEntityClass(String tableName, Class clazz) throws NoSuchMethodException {
        tableEntityClassCacheMap.put(tableName.toLowerCase(), clazz);
        tableInfoCacheMap.put(clazz, new TableInfo(clazz));
    }

    public static Class getTableEntityClass(String tableName) {
        return  tableEntityClassCacheMap.get(tableName.toLowerCase());
    }

    public static TableInfo getTableInfo(Class clazz) {
        return tableInfoCacheMap.get(clazz);
    }

    public static TableInfo getTableInfo(String tableName) {
        if(StrUtil.isEmpty(tableName)) {
            return null;
        }

        Class clazz = getTableEntityClass(tableName.trim());
        if(clazz == null) {
            return null;
        }

        return getTableInfo(clazz);
    }

    @Getter
    private List<Class> tableCacheClassList = null;

    @Autowired
    CacheConfig cacheConfig;

    @Autowired
    DynamicCacheWrite dynamicCacheWrite;

    @Autowired
    DynamicCache dynamicCache;

    @Autowired
    TableMapperService tableMapperService;

    @SneakyThrows
    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        applicationContext = contextRefreshedEvent.getApplicationContext();
        CacheDataLoad load = (CacheDataLoad) applicationContext.getBean("cacheDataLoad");
        load.init(applicationContext);

    }

//    @PostConstruct
    public void init() throws IOException,
            ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        init(null);
    }

    public void init(ApplicationContext ac) throws IOException,
            ClassNotFoundException, NoSuchMethodException, InvocationTargetException,
            IllegalAccessException {

        LogUtil.info("开始加载缓存数据");
        //扫描包，并且获取存在 TableCache 注解的 class
        String sannPath = cacheConfig.getScanpath();
        sannPath = "classpath:" + (sannPath.replaceAll("\\.", "/")) + "/**/*.class";
        tableCacheClassList = PackageScann.scannByAnno(sannPath, TableCache.class);
        ac = ac == null ? applicationContext : ac;

        if (CollectionUtil.isEmpty(CacheDataLoad.tableEntityClassCacheMap)){
            LogUtil.info("查找到缓存实体 bean 个数: " + tableCacheClassList.size());

            for (Class item : tableCacheClassList){
                TableCache tableCache = (TableCache) item.getAnnotation(TableCache.class);
                putTableEntityClass(tableCache.tableName().toLowerCase(), item);
            }
        }

        loadAllTable();

        loadListener(ac);

        LogUtil.info("缓存数据加载完毕");
    }

    public void loadAllTable() throws NoSuchMethodException,
            IllegalAccessException, InvocationTargetException {
        for (Class item : tableCacheClassList){
            loadTable(item);
        }
    }

    public void loadTable(Class tableCacheClass)
            throws InvocationTargetException, IllegalAccessException {

        TableCache tableCache = (TableCache) tableCacheClass.getAnnotation(TableCache.class);
        List datas = tableMapperService.selectAll(tableCache.tableName(), tableCacheClass);

        if (datas == null) {
            return;
        }

        TableInfo tableInfo = CacheDataLoad.tableInfoCacheMap.get(tableCacheClass);
        try {
            dynamicCacheWrite.addBatch(datas);
        }catch (Exception e) {
            LogUtil.error(e.getMessage(), e);
        }
        long size = dynamicCache.mapSize(tableInfo.getTableNameKey());
        LogUtil.info("缓存实体 " + tableCacheClass + ", 加载完毕, 缓存行数：" + size + ", 是否完整:" + (datas.size() == size));
    }

    public static TableInfo getTableInfoByName(String name) {
        Class classObj = tableEntityClassCacheMap.get(name);
        if (classObj == null) {
            return null;
        }

        return tableInfoCacheMap.get(classObj);
    }

    public void loadListener(ApplicationContext ac) {
        Map<String, SQLListener> sqlListenerMap = ac.getBeansOfType(SQLListener.class);
        ListenerExce.registerSQLListeners(sqlListenerMap.values());
        LogUtil.info("sqlListener count: " + sqlListenerMap.size() );

        Map<String, ConnectionListener> connListenerMap = ac.getBeansOfType(ConnectionListener.class);
        ListenerExce.registerConnListener(connListenerMap.values());
        LogUtil.info("connListenerMap count: " + connListenerMap.size() );
    }
}
